"""
日志与成本统计模块
"""
import csv
import json
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, Optional
from loguru import logger
import sys
import time
import functools


def setup_logging(log_dir: str = "./logs", level: str = "INFO"):
    """
    设置日志配置
    
    Args:
        log_dir: 日志目录
        level: 控制台日志级别
    """
    log_path = Path(log_dir)
    log_path.mkdir(parents=True, exist_ok=True)
    
    # 移除默认handler
    logger.remove()
    
    # 1. 控制台输出（精简格式，用户友好）
    logger.add(
        sys.stdout,
        format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <level>{message}</level>",
        level=level,
        colorize=True,
        filter=lambda record: record["level"].name != "TRACE"  # 过滤TRACE级别
    )
    
    # 2. 主日志文件（详细记录，按日期+时间轮转）
    logger.add(
        log_path / f"storyforge_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log",
        rotation="500 MB",  # 单文件最大500MB
        retention="30 days",  # 保留30天
        compression="zip",  # 压缩旧日志
        encoding="utf-8",
        level="DEBUG",
        format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} | {message}",
        enqueue=True,  # 异步写入，提高性能
    )
    
    # 3. 错误日志文件（单独记录ERROR及以上级别）
    logger.add(
        log_path / f"error_{datetime.now().strftime('%Y%m%d')}.log",
        rotation="1 day",  # 每天一个新文件
        retention="90 days",  # 错误日志保留90天
        compression="zip",
        encoding="utf-8",
        level="ERROR",
        format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} | {message}\n{exception}",
        enqueue=True,
    )
    
    # 4. 性能日志文件（记录TRACE级别，用于性能分析）
    logger.add(
        log_path / f"performance_{datetime.now().strftime('%Y%m%d')}.log",
        rotation="1 day",
        retention="7 days",  # 性能日志保留7天
        encoding="utf-8",
        level="TRACE",
        format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {extra[duration]:.3f}s | {name}:{function} | {message}",
        enqueue=True,
        filter=lambda record: "duration" in record["extra"]  # 只记录包含duration的日志
    )
    
    logger.info(f"日志系统已初始化，日志目录: {log_path}")


def log_function_call(func):
    """
    装饰器：记录函数调用和执行时间
    
    使用方法：
        @log_function_call
        def my_function(arg1, arg2):
            pass
    """
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        func_name = f"{func.__module__}.{func.__qualname__}"
        
        # 记录函数调用
        logger.debug(f"调用函数: {func_name}")
        
        # 记录参数（对于敏感参数需要过滤）
        args_repr = []
        for i, arg in enumerate(args):
            if i == 0 and hasattr(arg, '__class__'):
                # 跳过self/cls参数
                args_repr.append(f"self={arg.__class__.__name__}")
            else:
                args_repr.append(repr(arg)[:100])  # 限制长度
        
        kwargs_repr = [f"{k}={repr(v)[:100]}" for k, v in kwargs.items() 
                      if k not in ['api_key', 'apiKey', 'password', 'token']]  # 过滤敏感参数
        
        all_args = ", ".join(args_repr + kwargs_repr)
        if all_args:
            logger.debug(f"  参数: {all_args}")
        
        # 执行函数并计时
        start_time = time.time()
        try:
            result = func(*args, **kwargs)
            duration = time.time() - start_time
            
            # 记录执行时间（使用TRACE级别用于性能分析）
            logger.bind(duration=duration).trace(f"函数执行完成: {func_name}")
            logger.debug(f"函数执行成功: {func_name}, 耗时: {duration:.3f}秒")
            
            return result
        except Exception as e:
            duration = time.time() - start_time
            logger.error(f"函数执行失败: {func_name}, 耗时: {duration:.3f}秒, 错误: {e}")
            logger.exception(f"异常详情:")
            raise
    
    return wrapper


class LogContext:
    """
    日志上下文管理器，用于记录代码块的执行情况
    
    使用方法：
        with LogContext("处理大纲", logger):
            # 代码块
            pass
    """
    
    def __init__(self, description: str, log_level: str = "INFO"):
        """
        初始化日志上下文
        
        Args:
            description: 操作描述
            log_level: 日志级别
        """
        self.description = description
        self.log_level = log_level
        self.start_time = None
    
    def __enter__(self):
        """进入上下文"""
        self.start_time = time.time()
        logger.log(self.log_level, f"开始: {self.description}")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """退出上下文"""
        duration = time.time() - self.start_time
        
        if exc_type is None:
            # 成功完成
            logger.bind(duration=duration).trace(f"操作完成: {self.description}")
            logger.log(self.log_level, f"完成: {self.description}, 耗时: {duration:.3f}秒")
        else:
            # 发生异常
            logger.error(f"失败: {self.description}, 耗时: {duration:.3f}秒, 错误: {exc_val}")
            logger.exception(f"异常详情:")
        
        return False  # 不抑制异常


def log_cost(
    project: str,
    cost_type: str,
    provider: str,
    tokens_or_items: int,
    unit_cost: float,
    total: float,
    log_dir: str = "./logs",
    use_database: bool = True
) -> None:
    """
    记录成本到数据库和CSV（向后兼容）
    
    Args:
        project: 项目名称
        cost_type: 成本类型（llm/image/tts等）
        provider: 提供商
        tokens_or_items: token数或物品数
        unit_cost: 单价
        total: 总成本
        log_dir: 日志目录
        use_database: 是否使用数据库（默认True）
    """
    # 写入数据库
    if use_database:
        try:
            from .database import log_cost_to_db
            log_cost_to_db(
                project=project,
                cost_type=cost_type,
                provider=provider,
                tokens_or_items=tokens_or_items,
                unit_cost=unit_cost,
                total=total
            )
        except Exception as e:
            logger.error(f"记录成本到数据库失败: {e}")
    
    # 同时写入CSV（向后兼容）
    csv_path = Path(log_dir) / "cost.csv"
    file_exists = csv_path.exists()
    
    try:
        with open(csv_path, 'a', newline='', encoding='utf-8') as f:
            writer = csv.writer(f)
            if not file_exists:
                writer.writerow(["timestamp", "project", "type", "provider", "tokens/items", "unit_cost", "total"])
            writer.writerow([
                datetime.now().isoformat(),
                project,
                cost_type,
                provider,
                tokens_or_items,
                unit_cost,
                total
            ])
        logger.info(f"成本记录: {cost_type} {provider} ${total:.4f}")
    except Exception as e:
        logger.error(f"记录成本到CSV失败: {e}")


def log_job(job: Dict[str, Any], log_dir: str = "./logs") -> None:
    """
    记录任务状态到JSONL
    
    Args:
        job: 任务字典
        log_dir: 日志目录
    """
    jsonl_path = Path(log_dir) / "jobs.jsonl"
    try:
        with open(jsonl_path, 'a', encoding='utf-8') as f:
            json.dump(job, f, ensure_ascii=False, default=str)
            f.write('\n')
    except Exception as e:
        logger.error(f"记录任务失败: {e}")


def log_role_run(role_run: Dict[str, Any], log_dir: str = "./logs") -> None:
    """
    记录角色运行到JSONL
    
    Args:
        role_run: 角色运行字典
        log_dir: 日志目录
    """
    jsonl_path = Path(log_dir) / "roles.jsonl"
    try:
        with open(jsonl_path, 'a', encoding='utf-8') as f:
            json.dump(role_run, f, ensure_ascii=False, default=str)
            f.write('\n')
    except Exception as e:
        logger.error(f"记录角色运行失败: {e}")


def get_cost_report(
    project: Optional[str] = None, 
    log_dir: str = "./logs",
    use_database: bool = True
) -> Dict[str, Any]:
    """
    获取成本报告（优先从数据库读取）
    
    Args:
        project: 项目名称，None表示所有项目
        log_dir: 日志目录
        use_database: 是否使用数据库（默认True）
        
    Returns:
        成本统计字典
    """
    # 优先从数据库读取
    if use_database:
        try:
            from .database import get_cost_report as get_cost_report_from_db
            return get_cost_report_from_db(project=project)
        except Exception as e:
            logger.warning(f"从数据库读取成本报告失败，回退到CSV: {e}")
    
    # 回退到CSV
    csv_path = Path(log_dir) / "cost.csv"
    if not csv_path.exists():
        return {"total": 0.0, "by_type": {}, "by_provider": {}}
    
    total = 0.0
    by_type = {}
    by_provider = {}
    
    try:
        with open(csv_path, 'r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            for row in reader:
                if project and row.get('project') != project:
                    continue
                cost = float(row.get('total', 0))
                total += cost
                cost_type = row.get('type', 'unknown')
                by_type[cost_type] = by_type.get(cost_type, 0) + cost
                provider = row.get('provider', 'unknown')
                by_provider[provider] = by_provider.get(provider, 0) + cost
    except Exception as e:
        logger.error(f"读取成本报告失败: {e}")
        return {"total": 0.0, "by_type": {}, "by_provider": {}}
    
    return {
        "total": total,
        "by_type": by_type,
        "by_provider": by_provider
    }

